package com.tang.subject.domain.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.tang.common.entity.PageResult;
import com.tang.common.enums.DeleteEnum;
import com.tang.subject.common.consts.ThreadNameConst;
import com.tang.subject.domain.convert.SubjectInfoConverter;
import com.tang.subject.domain.entity.SubjectInfoBO;
import com.tang.subject.domain.entity.SubjectOptionBO;
import com.tang.subject.domain.handler.subject.SubjectTypeHandler;
import com.tang.subject.domain.handler.subject.SubjectTypeHandlerFactory;
import com.tang.subject.domain.service.SubjectInfoDomainService;
import com.tang.subject.infra.basic.entity.es.SubjectInfoEs;
import com.tang.subject.infra.basic.entity.pojo.SubjectInfo;
import com.tang.subject.infra.basic.entity.pojo.SubjectLabel;
import com.tang.subject.infra.basic.entity.pojo.SubjectMapping;
import com.tang.subject.infra.basic.service.SubjectEsService;
import com.tang.subject.infra.basic.service.SubjectInfoService;
import com.tang.subject.infra.basic.service.SubjectLabelService;
import com.tang.subject.infra.basic.service.SubjectMappingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SubjectInfoDomainServiceImpl implements SubjectInfoDomainService {

    @Resource
    private SubjectInfoService subjectInfoService;

    @Resource
    private SubjectTypeHandlerFactory subjectTypeHandlerFactory;

    @Resource
    private SubjectMappingService subjectMappingService;

    @Resource
    private SubjectLabelService subjectLabelService;

    @Resource
    private SubjectEsService subjectEsService;

    @Resource(name = ThreadNameConst.ES_THREAD_POLL)
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    /**
     * 新增题目
     *
     * @param subjectInfoBO 待添加的题目信息
     * @return java.lang.Boolean
     * @author Tang
     * @date 2024/2/4 13:28
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addSubjectInfo(SubjectInfoBO subjectInfoBO) {
        try {
            if (log.isInfoEnabled()) {
                log.info("SubjectInfoDomainService.addSubjectInfo.bo:{}", subjectInfoBO);
            }
            //插入题目信息
            SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBoToEntity(subjectInfoBO);
            subjectInfo.setIsDeleted(DeleteEnum.UN_DELETED.getCode());
            subjectInfoService.insert(subjectInfo);
            //回填题目id，方便后续操作
            subjectInfoBO.setId(subjectInfo.getId());
            //根据题型插入不同的表中
            SubjectTypeHandler handler = subjectTypeHandlerFactory.getHandler(subjectInfoBO.getSubjectType());
            handler.add(subjectInfoBO);
            //插入题目与分类、标签的关联
            List<SubjectMapping> subjectMappingList = getCategoryAndLabelCombine(subjectInfoBO);
            subjectMappingService.insertBatch(subjectMappingList);
            //异步执行es同步逻辑
            threadPoolTaskExecutor.submit(() -> synchronizeToEs(subjectInfo));
            return true;
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                log.error("SubjectInfoDomainService.addSubjectInfo.error:{}", subjectInfoBO, e);
            }
            return false;
        }
    }

    /**
     * 同步数据到es
     *
     * @param subjectInfo 题目基本信息
     * @author Tang
     * @date 2024/2/23 21:15
     **/
    private void synchronizeToEs(SubjectInfo subjectInfo) {
        SubjectInfoEs subjectInfoEs = SubjectInfoConverter.INSTANCE.convertInfoToEs(subjectInfo);
        subjectInfoEs.setDocId(IdWorker.getId());
        subjectInfoEs.setSubjectId(subjectInfo.getId());
        subjectEsService.insert(subjectInfoEs);
    }

    /**
     * 查询题目列表
     *
     * @param subjectInfoBO 查询条件
     * @return com.tang.subject.common.entity.PageResult<com.tang.subject.domain.entity.SubjectInfoBO>
     * @author Tang
     * @date 2024/2/4 17:15
     **/
    @Override
    public PageResult<SubjectInfoBO> getSubjectPage(SubjectInfoBO subjectInfoBO) {
        try {
            if (log.isInfoEnabled()) {
                log.info("SubjectInfoDomainService.getSubjectPage.bo:{}", JSON.toJSONString(subjectInfoBO));
            }
            PageResult<SubjectInfoBO> pageResult = new PageResult<>();
            pageResult.setPageNo(subjectInfoBO.getPageNo());
            pageResult.setPageSize(subjectInfoBO.getPageSize());
            int start = (subjectInfoBO.getPageNo() - 1) * subjectInfoBO.getPageSize();
            SubjectInfo subjectInfo = SubjectInfoConverter.INSTANCE.convertBoToEntity(subjectInfoBO);
            int count = subjectInfoService.countByCondition(subjectInfo,
                    subjectInfoBO.getCategoryId(),
                    subjectInfoBO.getLabelId());
            if (Objects.equals(count, 0)) {
                return pageResult;
            }
            List<SubjectInfo> subjectInfos = subjectInfoService.queryPage(subjectInfo,
                    subjectInfoBO.getCategoryId(),
                    subjectInfoBO.getLabelId(),
                    start,
                    subjectInfoBO.getPageSize());
            List<SubjectInfoBO> subjectInfoBOS = SubjectInfoConverter.INSTANCE.convertInfoListToBo(subjectInfos);
            pageResult.setRecords(subjectInfoBOS);
            pageResult.setTotal(count);
            return pageResult;
        } catch (Exception e) {
            if (log.isErrorEnabled()) {
                log.info("SubjectInfoDomainService.getSubjectPage.error:{}", subjectInfoBO, e);
            }
            return null;
        }
    }

    /**
     * 查询题目详细信息
     *
     * @param query 查询条件
     * @return com.tang.subject.domain.entity.SubjectInfoBO
     * @author Tang
     * @date 2024/2/5 17:40
     **/
    @Override
    public SubjectInfoBO querySubjectInfo(SubjectInfoBO query) {
        try {
            if (log.isInfoEnabled()) {
                log.info("SubjectInfoDomainService.querySubjectInfo.bo:{}", JSON.toJSONString(query));
            }
            //查询题目基本信息
            SubjectInfo basicInfo = subjectInfoService.queryById(query.getId());
            if (Objects.isNull(basicInfo)) {
                return null;
            }
            //查询题目选项数据
            SubjectOptionBO subjectOptionBO = queryOptionBo(basicInfo);
            //查询与题目相关联的标签
            List<String> labelList = queryLabelList(query);
            //包装并返回的题目信息对象
            return buildSubjectInfoBo(subjectOptionBO, basicInfo, labelList);
        } catch (Exception e) {
            log.info("SubjectInfoDomainService.querySubjectInfo.error:{}", JSON.toJSONString(query), e);
            return null;
        }
    }

    /**
     * 通过关键词全文检索题目选项
     *
     * @param search 检索条件
     * @return com.tang.common.entity.PageResult<com.tang.subject.domain.entity.SubjectInfoBO>
     * @author Tang
     * @date 2024/2/24 14:37
     **/
    @Override
    public PageResult<SubjectInfoBO> searchSubjectInfo(SubjectInfoBO search) {
        try {
            if (log.isInfoEnabled()) {
                log.info("SubjectInfoDomainService.searchSubjectInfo.bo:{}", JSON.toJSONString(search));
            }
            SubjectInfoEs subjectInfoEs = SubjectInfoConverter.INSTANCE.convertBOToES(search);
            PageResult<SubjectInfoEs> pageResult = subjectEsService.querySubjectList(subjectInfoEs);
            return pageResult.convert(SubjectInfoConverter.INSTANCE::convertEsToBo);
        } catch (Exception e) {
            log.info("SubjectInfoDomainService.searchSubjectInfo.error:{}", JSON.toJSONString(search), e);
            return null;
        }
    }

    //构建SubjectInfoBo返回体
    private static SubjectInfoBO buildSubjectInfoBo(SubjectOptionBO subjectOptionBO, SubjectInfo basicInfo, List<String> labelList) {
        SubjectInfoBO subjectInfoBO = SubjectInfoConverter.INSTANCE
                .convertOptionBoAndInfoToBo(subjectOptionBO, basicInfo);
        subjectInfoBO.setLabelName(labelList);
        return subjectInfoBO;
    }

    //查询题目选项数据
    private SubjectOptionBO queryOptionBo(SubjectInfo query) {
        Integer subjectType = query.getSubjectType();
        SubjectTypeHandler handler = subjectTypeHandlerFactory.getHandler(subjectType);
        return handler.query(query.getId());
    }

    //查询与题目相关联的标签名称列表
    private List<String> queryLabelList(SubjectInfoBO query) {
        SubjectMapping subjectMapping = new SubjectMapping();
        subjectMapping.setSubjectId(query.getId());
        subjectMapping.setIsDeleted(DeleteEnum.UN_DELETED.getCode());
        List<Long> labelIds = subjectMappingService.queryLabel(subjectMapping).stream()
                .filter(Objects::nonNull)
                .map(SubjectMapping::getLabelId)
                .collect(Collectors.toList());
        return subjectLabelService.queryBatch(labelIds)
                .stream()
                .filter(Objects::nonNull)
                .map(SubjectLabel::getLabelName)
                .collect(Collectors.toList());
    }

    //组合分类id和标签id
    private List<SubjectMapping> getCategoryAndLabelCombine(SubjectInfoBO subjectInfoBO) {
        List<SubjectMapping> subjectMappings = new ArrayList<>();
        List<Long> categoryIds = subjectInfoBO.getCategoryIds();
        List<Long> labelIds = subjectInfoBO.getLabelIds();
        categoryIds.forEach(categoryId -> {
            labelIds.forEach(labelId -> {
                SubjectMapping subjectMapping = new SubjectMapping();
                subjectMapping.setSubjectId(subjectInfoBO.getId());
                subjectMapping.setCategoryId(categoryId);
                subjectMapping.setLabelId(labelId);
                subjectMappings.add(subjectMapping);
            });
        });
        return subjectMappings;
    }
}
